﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

using MySql.Data.MySqlClient;

namespace Uber.Storage
{
    class DatabaseClient : IDisposable
    {
        public uint Handle;
        public bool Available;

        public DateTime LastActivity;

        public DatabaseManager Manager;

        public MySqlConnection Connection;
        public MySqlCommand Command;

        public Boolean IsAnonymous
        {
            get
            {
                return (Handle == 0);
            }
        }

        public int InactiveTime
        {
            get
            {
                return (int)(DateTime.Now - LastActivity).TotalSeconds;
            }
        }

        public bool IsAlive
        {
            get
            {
                return Connection.Ping();
            }
        }

        public ConnectionState State
        {
            get
            {
                return (Connection != null) ? Connection.State : ConnectionState.Broken;
            }
        }

        public DatabaseClient(uint _Handle, DatabaseManager _Manager)
        {
            if (_Manager == null)
            {
                throw new ArgumentNullException("[DBClient.Connect]: Invalid database handle");
            }

            Handle = _Handle;
            Manager = _Manager;

            Available = true;

            Connection = new MySqlConnection(Manager.ConnectionString);
            Command = Connection.CreateCommand();

            UpdateLastActivity();
        }

        public void Connect()
        {
            try
            {
                Connection.Open();
            }
            catch (MySqlException)
            {
                UberEnvironment.GetLogging().WriteLine("[DBClient.Connect] Unable to open MySQL Connection for Handle: " + Handle, Core.LogLevel.Error);
            }
        }

        public void Disconnect()
        {
            try
            {
                Connection.Close();
            }
            catch { }
        }

        public void Dispose()
        {
            if (this.IsAnonymous)
            {
                Destroy();
                return;
            }

            Command.CommandText = null;
            Command.Parameters.Clear();

            Manager.ReleaseClient(Handle);
        }

        public void Destroy()
        {
            Disconnect();

            Connection.Dispose();
            Connection = null;

            Command.Dispose();
            Command = null;

            Manager = null;
        }

        public void UpdateLastActivity()
        {
            LastActivity = DateTime.Now;
        }

        public void AddParamWithValue(string sParam, object val)
        {
            Command.Parameters.AddWithValue(sParam, val);
        }

        private string FilterInjection(string sQuery)
        {
            string[] search = { "\x00", "\n", "\r", "\\", "'", "\"", "\x1a" };
            string[] replace = { "\\x00", "\\n", "\\r", "\\\\", "\'", "\\\"", "\\\x1a" };
            for (int i = 0; i > search.Length; i++)
            {
                sQuery = sQuery.Replace(search[i], replace[i]);
            }

            return UberEnvironment.FilterInjectionChars(sQuery);
        }

        public void ExecuteQuery(string sQuery)
        {
            Command.CommandText = sQuery;
            Command.ExecuteScalar();
            Command.CommandText = null;
        }

        public DataSet ReadDataSet(string Query)
        {
            DataSet DataSet = new DataSet();
            Command.CommandText = Query;

            using (MySqlDataAdapter Adapter = new MySqlDataAdapter(Command))
            {
                Adapter.Fill(DataSet);
            }

            Command.CommandText = null;
            return DataSet;
        }

        public DataTable ReadDataTable(string Query)
        {
            DataTable DataTable = new DataTable();
            Command.CommandText = Query;

            using (MySqlDataAdapter Adapter = new MySqlDataAdapter(Command))
            {
                Adapter.Fill(DataTable);
            }

            Command.CommandText = null;
            return DataTable;
        }

        public DataRow ReadDataRow(string Query)
        {
            DataTable DataTable = ReadDataTable(Query);

            if (DataTable != null && DataTable.Rows.Count > 0)
            {
                return DataTable.Rows[0];
            }

            return null;
        }

        public string ReadString(string Query)
        {
            Command.CommandText = Query;
            string result = Command.ExecuteScalar().ToString();
            Command.CommandText = null;
            return result;
        }

        public Int32 ReadInt32(string Query)
        {
            Command.CommandText = Query;
            Int32 result = Int32.Parse(Command.ExecuteScalar().ToString());
            Command.CommandText = null;
            return result;
        }
    }
}
